<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <h2>一、前言</h2>
  <div>下拉刷新和上拉加载这两种交互方式通常出现在移动端中,本质上等同于PC网页中的分页，只是交互形式不同</div>
  <br>
  <div>开源社区也有很多优秀的解决方案，如iscroll、better-scroll、pulltorefresh.js库等等</div>
  <h2>二、实现原理</h2>
  <h4>上拉加载</h4>
  <div>上拉加载的本质是页面触底，或者快要触底时的动作</div>
  <br>
  <div>判断页面触底我们需要先了解一下下面几个属性</div>
  <ul>
    <li>scrollTop：滚动视窗的高度距离window顶部的距离，它会随着往上滚动而不断增加，初始值是0，它是一个变化的值</li>
    <li>clientHeight:它是一个定值，表示屏幕可视区域的高度；</li>
    <li>scrollHeight：页面不能滚动时是不存在的，body长度超过window时才会出现，所表示body所有元素的长度</li>
    <li>scrollTop + clientHeight >= scrollHeight</li>
  </ul>
  <script>
    let clientHeight  = document.documentElement.clientHeight; //浏览器高度
    let scrollHeight = document.body.scrollHeight;
    let scrollTop = document.documentElement.scrollTop;
    let distance = 50;  //距离视窗还用50的时候，开始触发；
    if ((scrollTop + clientHeight) >= (scrollHeight - distance)) {
        console.log("开始加载数据");
    }
  </script>
  <div>
    <h4>下拉刷新</h4>
    <div>下拉刷新的本质是页面本身置于顶部时，用户下拉时需要触发的动作</div>
    <br>
    <div>关于下拉刷新的原生实现，主要分成三步：</div>
    <ul>
      <li>监听原生touchstart事件，记录其初始位置的值，e.touches[0].pageY；</li>
      <li>监听原生touchmove事件，记录并计算当前滑动的位置值与初始位置值的差值，大于0表示向下拉动，并借助CSS3的translateY属性使元素跟随手势向下滑动对应的差值，同时也应设置一个允许滑动的最大值；</li>
      <li>监听原生touchend事件，若此时元素滑动达到最大值，则触发callback，同时将translateY重设为0，元素回到初始位置</li>
    </ul>
  </div>
  <main>
    <p class="refreshText"></p>
    <ul id="refreshContainer">
        <li>111</li>
        <li>222</li>
        <li>333</li>
        <li>444</li>
        <li>555</li>
    </ul>
  </main>
  <script>
    // 监听touchstart事件，记录初始的值
    var _element = document.getElementById('refreshContainer'),
        _refreshText = document.querySelector('.refreshText'),
        _startPos = 0,  // 初始的值
        _transitionHeight = 0; // 移动的距离

    _element.addEventListener('touchstart', function(e) {
        _startPos = e.touches[0].pageY; // 记录初始位置
        _element.style.position = 'relative';
        _element.style.transition = 'transform 0s';
    }, false);
    // 监听touchmove移动事件，记录滑动差值
    _element.addEventListener('touchmove', function(e) {
    // e.touches[0].pageY 当前位置
    _transitionHeight = e.touches[0].pageY - _startPos; // 记录差值

    if (_transitionHeight > 0 && _transitionHeight < 60) { 
        _refreshText.innerText = '下拉刷新'; 
        _element.style.transform = 'translateY('+_transitionHeight+'px)';

        if (_transitionHeight > 55) {
            _refreshText.innerText = '释放更新';
        }
      }                
    }, false);
    // 最后，就是监听touchend离开的事件
    _element.addEventListener('touchend', function(e) {
    _element.style.transition = 'transform 0.5s ease 1s';
    _element.style.transform = 'translateY(0px)';
    _refreshText.innerText = '更新中...';
    // todo...

    }, false);
  </script>
  <div>
    <div>从上面可以看到，在下拉到松手的过程中，经历了三个阶段：</div>
    <ul>
      <li>当前手势滑动位置与初始位置差值大于零时，提示正在进行下拉刷新操作</li>
      <li>下拉到一定值时，显示松手释放后的操作提示</li>
      <li>下拉到达设定最大值松手时，执行回调，提示正在进行更新操作</li>
    </ul>
  </div>
  <div>
    <h2>三、案例</h2>
    <div>在实际开发中，我们更多的是使用第三方库</div>
  </div>
  <h2>小结</h2>
  <div>下拉刷新、上拉加载原理本身都很简单，真正复杂的是封装过程中，要考虑的兼容性、易用性、性能等诸多细节</div>
</body>
</html>